using System;
using System.Collections;
using System.Collections.Generic;

namespace LightCAD.Three
{
    public class Line3
    {
        #region scope properties or methods
        //private static Vector3 _startP = new Vector3();
        //private static Vector3 _startEnd = new Vector3();
        private static Line3Context getContext()
        {
            return ThreadContext.getCurrThreadContext().Line3Ctx;
        }
        #endregion

        #region Properties

        public Vector3 start;
        public Vector3 end;

        #endregion

        #region constructor
        public Line3(Vector3 start = null, Vector3 end = null)
        {
            if (start == null) start = new Vector3();
            if (end == null) end = new Vector3();
            this.start = start;
            this.end = end;
        }
        #endregion

        #region methods
        public Line3 set(Vector3 start, Vector3 end)
        {
            this.start.copy(start);
            this.end.copy(end);
            return this;
        }
        public Line3 copy(Line3 line)
        {
            this.start.copy(line.start);
            this.end.copy(line.end);
            return this;
        }
        public Vector3 getCenter(Vector3 target = null)
        {
            target = target ?? new Vector3();
            return target.addVectors(this.start, this.end).multiplyScalar(0.5);
        }
        public Vector3 delta(Vector3 target = null)
        {
            target = target ?? new Vector3();
            return target.subVectors(this.end, this.start);
        }
        public double distanceSq()
        {
            return this.start.distanceToSquared(this.end);
        }
        public double distance()
        {
            return this.start.distanceTo(this.end);
        }
        public Vector3 at(double t, Vector3 target)
        {
            return this.delta(target).multiplyScalar(t).add(this.start);
        }
        public double closestPointToPointParameter(Vector3 point, bool clampToLine)
        {
            var _startP = getContext()._startP;
            var _startEnd = getContext()._startEnd;
            _startP.subVectors(point, this.start);
            _startEnd.subVectors(this.end, this.start);
            double startEnd2 = _startEnd.dot(_startEnd);
            double startEnd_startP = _startEnd.dot(_startP);
            double t = startEnd_startP / startEnd2;
            if (clampToLine)
            {
                t = MathUtils.clamp(t, 0, 1);
            }
            return t;
        }
        public Vector3 closestPointToPoint(Vector3 point, bool clampToLine, Vector3 target)
        {
            double t = this.closestPointToPointParameter(point, clampToLine);
            return this.delta(target).multiplyScalar(t).add(this.start);
        }
        public Line3 applyMatrix4(Matrix4 matrix)
        {
            this.start.applyMatrix4(matrix);
            this.end.applyMatrix4(matrix);
            return this;
        }
        public bool equals(Line3 line)
        {
            return line.start.equals(this.start) && line.end.equals(this.end);
        }
        public Line3 clone()
        {
            return new Line3().copy(this);
        }
        #endregion

    }
}
